import { ipcMain } from 'electron'
import fsExtra from 'fs-extra'
import path from 'node:path'
import type { IpcMainInvokeEvent } from 'electron'

/**
 * 根据 tableDataItem 生成文件 / 目录的完整路径,若路径在磁盘上已经存在则会添加索引,直至不存在为止
 * @param item 一条文件 / 目录数据
 * @param saveMethod 保存方式: 0 覆盖原文件、1 移动至、2 另存至
 * @param targetDir 目标目录
 * @param extIndex 后缀索引
 * @param set 存储已经重命名的文件 / 目录的完整路径,用于覆盖原文件时检测出的已经存在路径,是原路径还是从其他文件命名过来的
 */
function newFullPath(
  saveMethod: '0' | '1' | '2',
  targetDir: string | undefined
) {
  // 后缀索引
  let extIndex = 1
  // 存储已经重命名的文件 / 目录的完整路径,用于覆盖原文件时检测出的已经存在路径,是原路径还是从其他文件命名过来的
  const set = new Set<string>()

  async function calNewFullPath(item: ITableDataItem) {
    // 目标路径(目标文件 / 目录名)
    let directoryPath: string
    // 目标文件 / 目录名
    let targetName: string

    // 不需要添加索引
    if (extIndex === 1) {
      targetName = `${item.newest.name}`
    } else {
      targetName = `${item.newest.name}(${extIndex})`
    }

    // 如果有后缀则拼接
    if (item.newest.ext) {
      targetName += `.${item.newest.ext}`
    }

    // 目录路径(不包括目标文件 / 目录名)
    if (saveMethod === '0') {
      directoryPath = item.path
    } else {
      directoryPath = targetDir!
    }

    // 完整路径(包括目标文件 / 目录名)
    const fullFilePath = path.join(directoryPath, targetName)
    // 判定传入的路径,在磁盘上是否已经存在
    const exists = await fsExtra.pathExists(fullFilePath)

    // 如果文件 / 目录已存在
    if (exists) {
      // 如果是覆盖原文件,则判定是否是原文件(set 中有,则认为是其他文件命名过来的,如果没有,则判定已经存在的就是原文件)
      if (saveMethod === '0' && !set.has(fullFilePath)) {
        set.add(fullFilePath)
        return fullFilePath
      }

      extIndex++
      return calNewFullPath(item)
    } else {
      // 索引如果被使用过,则添加后缀
      if (extIndex > 1) {
        item.newest.name = `${item.newest.name}(${extIndex})`
      }

      set.add(fullFilePath)
      return fullFilePath
    }
  }

  return calNewFullPath
}

/**
 * 执行文件 / 文件夹重命名
 *    tableData 文件数据
 *    saveMethod 覆盖原文件、移动至、另存至
 *    targetDir 移动至或另存至的目标文件夹
 */
ipcMain.handle(
  'executeFileRename',
  async (
    _event: IpcMainInvokeEvent,
    tableData: ITableDataItem[],
    saveMethod: '0' | '1' | '2',
    targetDir: string | undefined
  ): Promise<ITableDataItem[]> => {
    if (tableData.length > 0) {
      let actFn: (fullPath: string, newFullPath: string) => Promise<void>
      if (saveMethod === '0') {
        // 覆盖原文件
        actFn = async (fullPath: string, newFullPath: string) => {
          await fsExtra.rename(fullPath, newFullPath)
        }
      } else if (saveMethod === '1') {
        // 移动至
        actFn = async (fullPath: string, newFullPath: string) => {
          await fsExtra.move(fullPath, newFullPath)
        }
      } else {
        // 另存至
        actFn = async (fullPath: string, newFullPath: string) => {
          await fsExtra.copy(fullPath, newFullPath)
        }
      }

      // 获取计算路径的函数
      const calNewFullPath = newFullPath(saveMethod, targetDir)

      for (let i = 0; i < tableData.length; i++) {
        const item = tableData[i]

        try {
          // 文件 / 目录的完整路径
          const newFullPath = await calNewFullPath(item)
          await actFn(item.fullPath, newFullPath)

          // 重命名成功
          item.state = '40'
          item.original.name = item.newest.name
          item.original.ext = item.newest.ext
          item.fullPath = newFullPath
        } catch (error) {
          const code = error.code
          if (code === 'ENOENT') {
            // 文件或目录不存在
            item.state = '60'
          } else {
            // 无权限访问
            item.state = '50'
          }
        }
      }
    }

    return tableData
  }
)
